

#include <sudoku.h>

#include <stdlib.h>

//#define _DEBUG


void sdk_print_sudoku(FILE *stream, sudoku *sdk){

  int i, j, k;

  for (i = 0; i < 3; i++){
    fprintf(stream, "++===+===+===++===+===+===++===+===+===++\n");
    for (j = 0; j < 3; j++){
      fprintf(stream, "][ %d | %d | %d ][ %d | %d | %d ][ %d | %d | %d ][\n",
	      (int)sdk->data[(i * 3) + j][0], (int)sdk->data[(i * 3) + j][1],
	      (int)sdk->data[(i * 3) + j][2], (int)sdk->data[(i * 3) + j][3],
	      (int)sdk->data[(i * 3) + j][4], (int)sdk->data[(i * 3) + j][5],
	      (int)sdk->data[(i * 3) + j][6], (int)sdk->data[(i * 3) + j][7],
	      (int)sdk->data[(i * 3) + j][8]);
    }
  }

  fprintf(stream, "++===+===+===++===+===+===++===+===+===++\n");

}

void sdk_print_sub_sudoku(FILE *stream, vm_matrix *mtx){

  vm_fprint_matrix(stream, mtx, " ");

}

sudoku *sdk_read_sudoku(char *file){

  return (sudoku *) vm_read_matrix(file);

}


sdk_error_info *sdk_legit_sudoku(sudoku *sdk){

  int row, col;

  // Preamble: make sure the sudoku is complete.
  for ( row = 0; row < 9; row++){
    for ( col = 0; col < 9; col++){
      if (SDK_GET_ELEM(sdk, row, col) == 0){
	sdk_error_info *err = (sdk_error_info *)malloc(sizeof(sdk_error_info));
	err->err_type = SDK_ERROR_INCOMPLETE;
	err->row = row;
	err->col = col;
      }
    }
  }

  // First check the submatrices.

  for ( row = 0; row < 3; row++){
    for ( col = 0; col < 3; col++){
      vm_matrix *mtx = sdk_sub_matrix(sdk, row, col);
      int r, c;
      int nums[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
      for ( r = 0; r < 3; r++){
	for ( c = 0; c < 3; c++){
	  if (nums[(int)SDK_GET_ELEM(mtx, r, c)] != 0){
	    nums[(int)SDK_GET_ELEM(mtx, r, c)] = 0;
	  } else { // We have more than one of the same num in the sub mtx
	    sdk_error_info *err = 
	      (sdk_error_info *)malloc(sizeof(sdk_error_info));
	    err->err_type = SDK_ERROR_BAD_SUBMTX;
	    err->row = r;
	    err->col = c;
	    err->submtx_row = row;
	    err->submtx_col = col;
	    return err;
	  }
	}
      }
    }
  }

  // Now check that the rows have 1-9 in them.
  for ( row = 0; row < 9; row++){
    vm_matrix *mtx = sdk_row(sdk, row);
    int nums[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int i;
    for ( i = 0; i < 9; i++){
      if (nums[(int)SDK_GET_ELEM(mtx, 0, i)] != 0){
	nums[(int)SDK_GET_ELEM(mtx, 0, i)] = 0;
      } else { // We have a bad row.
	sdk_error_info *err = 
	  (sdk_error_info *)malloc(sizeof(sdk_error_info));
	err->err_type = SDK_ERROR_BAD_ROW;
	err->row = row;
	err->col = i;
	return err;
      }
    }
  }

  // And now do the same for the columns.
  for ( col = 0; col < 9; col++){
    vm_matrix *mtx = sdk_col(sdk, col);
    int nums[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int i;
    for ( i = 0; i < 9; i++){
      if (nums[(int)SDK_GET_ELEM(mtx, 0, i)] != 0){
	nums[(int)SDK_GET_ELEM(mtx, 0, i)] = 0;
      } else { // We have a bad col.
	sdk_error_info *err = 
	  (sdk_error_info *)malloc(sizeof(sdk_error_info));
	err->err_type = SDK_ERROR_BAD_COL;
	err->row = i;
	err->col = col;
	return err;
      }
    }
  }

  // If no error found, return NULL.
  return NULL;

}

vm_matrix *sdk_enclosing_matrix(sudoku *sdk, int r, int c){

  char row = (char) (r / 3);
  char col = (char) (c / 3);

#  ifdef _DEBUG
  fprintf(stderr, "[sdk_enclosing_matrix] row=%d col=%d\n", row, col);
#  endif

  return sdk_sub_matrix(sdk, row, col);

}

vm_matrix *sdk_sub_matrix(sudoku *sdk, int sub_mtx_row, int sub_mtx_col){

#  ifdef _DEBUG
  fprintf(stderr, "[sdk_sub_matrix] row=%d col=%d\n", 
	  sub_mtx_row, sub_mtx_col);
#  endif

  vm_matrix *sub_mtx = vm_make_matrix(3, 3);
  int i, j;
  int row = 0, col = 0;
  
  for ( i = sub_mtx_row * 3; i < (sub_mtx_row + 1) * 3; i++){
    col = 0;
    for ( j = sub_mtx_col * 3; j < (sub_mtx_col + 1) * 3; j++){
      //printf("%d %d\n", i, j);
      //printf("%d %d\n--------\n", row, col);
      sub_mtx->data[row][col++] = SDK_GET_ELEM(sdk, row, col);
    }
    row++;
  }
  
  return sub_mtx;

}

vm_matrix *sdk_row(sudoku *sdk, int row){

  vm_matrix *mtx = vm_make_matrix(1, 9);
  
  int col = 0;
  for ( ; col < 9; col++){
    mtx->data[0][col] = SDK_GET_ELEM(sdk, row, col);
  }

  return mtx;

}

vm_matrix *sdk_col(sudoku *sdk, int col){

  vm_matrix *mtx = vm_make_matrix(1, 9);

  int row = 0;
  for ( ; row < 9; row++){
    mtx->data[0][row] = SDK_GET_ELEM(sdk, row, col);
  }

  return mtx;

}
